package com.roger.springcloudGreenwich.dao;

import com.alibaba.fastjson.JSON;
import com.roger.springcloudGreenwich.bean.Student;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Created by admin on 2020/3/30.
 */
@Service
@Slf4j
public class StudentDao {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public void highLevelBulkCreate(String index,String type,List<Student> docs) throws Exception{

        BulkRequest bulkRequest = new BulkRequest();
        //
        docs.forEach(batchRequest ->
                bulkRequest.add(
                        new IndexRequest(index, type, batchRequest.getId())
                                .source(XContentType.JSON, toArgs(batchRequest.getData())))
        );
        BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (response.hasFailures()) {
            log.error(response.buildFailureMessage());
        }
    }

    /**
     * 将批量数据转换成es参数数组
     * @param data
     * @return
     */
    private Object[] toArgs(Map<String, Object> data){
        List<Object> args = Lists.newArrayList();

        data.forEach((key, value) -> {
            args.add(key);
            args.add(value);
        });
        return args.toArray();
    }

    public void async(String index,String type,List<Student> docs){
        BulkRequest bulkRequest = new BulkRequest();
        docs.forEach(batchRequest ->
                bulkRequest.add(
                        new IndexRequest(index, type, batchRequest.getId())
                                .source(XContentType.JSON, toArgs(batchRequest.getData())))
        );
        ActionListener<BulkResponse> listener = new ActionListener<BulkResponse>() {
            @Override
            public void onResponse(BulkResponse bulkItemResponses) {
            }

            @Override
            public void onFailure(Exception e) {
            }
        };
        restHighLevelClient.bulkAsync(bulkRequest, RequestOptions.DEFAULT, listener);
    }

    public void query(int age) {
        try{
            // 1、创建search请求
            //SearchRequest searchRequest = new SearchRequest();
            SearchRequest searchRequest = new SearchRequest("students");
            searchRequest.types("_doc");

            // 2、用SearchSourceBuilder来构造查询请求体 ,请仔细查看它的方法，构造各种查询的方法都在这。
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            //构造QueryBuilder
            /*QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("user", "kimchy")
                    .fuzziness(Fuzziness.AUTO)
                    .prefixLength(3)
                    .maxExpansions(10);
            sourceBuilder.query(matchQueryBuilder);*/

            sourceBuilder.query(QueryBuilders.termQuery("age", age));
            sourceBuilder.from(0);
            sourceBuilder.size(10);
            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

            //将请求体加入到请求中
            searchRequest.source(sourceBuilder);

            //3、发送请求
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //4、处理响应
            //搜索结果状态信息
            RestStatus status = searchResponse.status();
            TimeValue took = searchResponse.getTook();
            Boolean terminatedEarly = searchResponse.isTerminatedEarly();
            boolean timedOut = searchResponse.isTimedOut();

            //分片搜索情况
            int totalShards = searchResponse.getTotalShards();
            int successfulShards = searchResponse.getSuccessfulShards();
            int failedShards = searchResponse.getFailedShards();
            for (ShardSearchFailure failure : searchResponse.getShardFailures()) {
                // failures should be handled here
            }

            //处理搜索命中文档结果
            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits();
            float maxScore = hits.getMaxScore();

            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                // do something with the SearchHit

                String index = hit.getIndex();
                String type = hit.getType();
                String id = hit.getId();
                float score = hit.getScore();

                //取_source字段值
                String sourceAsString = hit.getSourceAsString(); //取成json串
                Map<String, Object> sourceAsMap = hit.getSourceAsMap(); // 取成map对象
                //从map中取字段值
                /*
                String documentTitle = (String) sourceAsMap.get("title");
                List<Object> users = (List<Object>) sourceAsMap.get("user");
                Map<String, Object> innerObject = (Map<String, Object>) sourceAsMap.get("innerObject");
                */
                log.info("index:{},type:{},id:{}" , index , type ,id);
                log.info(sourceAsString);

                //取高亮结果
                /*Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlight = highlightFields.get("title");
                Text[] fragments = highlight.fragments();
                String fragmentString = fragments[0].string();*/
            }
        }catch(Exception e){
            e.printStackTrace();
            log.error("error:{}" ,e.getMessage());
        }

    }

    /**
     * 判断索引是否存在
     * @param index
     * @return
     */
    public boolean indexExist(String index){
        try {
            GetIndexRequest request = new GetIndexRequest();
            request.indices(index);
            request.local(false);
            request.humanReadable(true);
            request.includeDefaults(false);
            return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    public <T> List<T> listByBuilder(String[] indexArray, SearchSourceBuilder searchSourceBuilder, Class<T> c) {
        SearchRequest request = new SearchRequest(indexArray);
        searchSourceBuilder.trackTotalHits(true);
        request.source(searchSourceBuilder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            List<T> res = new ArrayList<>(hits.length);
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                String json = JSON.toJSONString(sourceAsMap);
                res.add(JSON.parseObject(json, c));
            }
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
